import type { IDisability, IValues, Scalar, WhenItem, OptionItem, WhenType } from './core';
import _ from 'lodash-es';

/**
 * # arr.splice(arr, start, deleteCount, ...items)
 */
export const arr_splice: <T = unknown>(
    arr: T[] | undefined,
    start: number,
    deleteCount?: number,
    ...items: T[]
) => Array<T> = (arr, start, deleteCount = 1, ...items) => {
    const temp = Array.isArray(arr) ? [...arr] : [];
    if (items) {
        temp.splice(start, deleteCount, ...items);
    } else {
        temp.splice(start, deleteCount);
    }
    return [...temp];
};
/**
 * # arr.push(...items)
 */
export const arr_push: <T = unknown>(arr?: T[], ...items: T[]) => Array<T> = (arr, ...items) => {
    const temp = Array.isArray(arr) ? [...arr] : [];
    temp.push(...items);
    return temp;
};

export const arr_can_up = (index: number, length: number) => index > 0 && index < length;
export const arr_can_down = (index: number, length: number) => index >= 0 && index < length - 1;
export const arr_up =  <T = unknown>(arr: T[], index: number): T[] => {
    const temp: T[] = [...arr];
    [temp[index-1], temp[index]] = [temp[index], temp[index-1]];
    return temp;
};

export const arr_down =  <T = unknown>(arr: T[], index: number): T[] => {
    const temp: T[] = [...arr];
    [temp[index+1], temp[index]] = [temp[index], temp[index+1]];
    return temp;
};



export const obj_update = <R = unknown, T extends string = string>(vs: IValues | undefined, name: T, v: R) => ({
    ...(vs || {}),
    [name]: v,
});
// noinspection JSUnusedGlobalSymbols
export const obj_remove = <T = IValues>(key: string, v?: T) => {
    return v ? _.omit(v as object, key) : {};
};

/**
 * # { [to]: props.[from].[value] ?? dft }
 */
export const value_of_arr = <F extends string = string, T extends string = string>(
    props: IValues,
    pairs: Array<[ks: F, k: T]>,
    value?: string | number,
) => {
    const p = {} as Record<T, unknown | undefined>;
    if (value === undefined) return p;

    pairs.forEach(([ks, k]) => {
        p[k] = (props[ks] as IValues)?.[value] ?? props[k];
    });

    return p;
};

// noinspection JSUnusedGlobalSymbols
export const string_is_empty = (v: unknown) => v === undefined || v === '' || v === null;
// noinspection JSUnusedGlobalSymbols
export const card2age = (card: string) => {
    if (!card || card.length !== 18) return undefined;

    const yearBirth = parseInt(card.substring(6, 10));
    const monthBirth = parseInt(card.substring(10, 12));

    const current = new Date();
    const monthNow = current.getMonth() + 1;
    let age = current.getFullYear() - yearBirth;
    if (monthNow < monthBirth) {
        age--;
    }
    //返回年龄
    return age;
};
// noinspection JSUnusedGlobalSymbols
export const card2birth = (card: string) => {
    if (!card || card.length !== 18) return undefined;

    return `${card.substring(6, 10)}.${card.substring(10, 12)}`;
};
// noinspection JSUnusedGlobalSymbols
export const card2Sex = (card: string) => parseInt(card.substring(16, 1)) % 2 === 1;
// noinspection JSUnusedGlobalSymbols
export const birth2age = (birth?: string) => {
    if (!birth) return undefined;
    return Math.ceil((new Date().getTime() - new Date(`birth-01`).getTime()) / 31536000000);
};
// noinspection JSUnusedGlobalSymbols
export const age2birth = (age: number) => {
    const n = new Date();
    const y = n.getFullYear() - age;
    const m = n.getMonth() + 1;

    return new Date(`${y}-${m}-1`).getTime();
};

/**
 * # 选项组转为数据对象
 * @param pairs
 * @param v2l
 */
export const options2obj = (pairs?: OptionItem[], v2l: boolean | string = false) => {
    if (!pairs) return undefined;

    if (v2l === true) v2l = 'label';
    const result: { [p: string]: string | number } = {};
    for (const pair of pairs) v2l ? (result[pair.value] = pair[v2l as 'label']) : (result[pair.label] = pair.value);

    return result;
};

// noinspection JSUnusedGlobalSymbols
/**
 * # 数据对象转为选项组
 * @param obj
 */
export const obj2options = (obj?: IValues) => {
    if (!obj) return [];

    return Object.getOwnPropertyNames(obj).map(
        (name) =>
            ({
                label: name,
                value: obj[name],
            }) as OptionItem,
    );
};

/**
 * # 方法-获取UUID
 */
export const get_uuid = () =>
    crypto?.randomUUID?.() ?? 'id_' + Math.random().toString(36) + Math.random().toString().slice(2);

/**
 * # 计算Disabled
 */
export function isDisabled(obj: IDisability, values?: IValues) {
    if (obj.disabled) return true;

    if (!(values && obj.when)) return false;

    const when =  obj.when;

    return check_when(when, values);
}

export function check_when(when: WhenType, values: IValues): boolean {
    for (const name in when) {
        const item = when[name];
        const input = values[name] as boolean | string | number | undefined;

        if (check_item(item, input)) continue;

        return true;
    }
    return false;
}

function check_item(item: WhenItem, input?: boolean | string | number) {
    // 有值才显示
    if (item === true) return input;
    // 无值才显示
    if (item === false) return !input;

    // 包含才显示
    if (Array.isArray(item) && input) return (item as Array<Scalar>).includes(input as Scalar);
    // 相同才显示
    if (item && input) return input !== item;

    return true;
}
